#!/usr/bin/env python
# -*- coding: utf-8 -*-

"""
测试脚本
测试RBAC权限控制装饰器的功能
"""

import unittest
import json
from app import create_app
from models import db, User, Role, Permission


class RBACTestCase(unittest.TestCase):
    """RBAC测试用例"""
    
    def setUp(self):
        """测试前准备"""
        self.app = create_app('testing')
        self.client = self.app.test_client()
        self.app_context = self.app.app_context()
        self.app_context.push()
        
        # 创建数据库表
        db.create_all()
        
        # 创建测试数据
        self._create_test_data()
    
    def tearDown(self):
        """测试后清理"""
        db.session.remove()
        db.drop_all()
        self.app_context.pop()
    
    def _create_test_data(self):
        """创建测试数据"""
        # 创建权限
        permissions = [
            Permission(name='user:read', resource='user', action='read'),
            Permission(name='user:create', resource='user', action='create'),
            Permission(name='user:update', resource='user', action='update'),
            Permission(name='user:delete', resource='user', action='delete'),
            Permission(name='content:read', resource='content', action='read'),
            Permission(name='content:create', resource='content', action='create'),
            Permission(name='content:publish', resource='content', action='publish'),
        ]
        for p in permissions:
            db.session.add(p)
        
        # 创建角色
        admin_role = Role(name='admin', description='管理员')
        admin_role.permissions = permissions
        db.session.add(admin_role)
        
        editor_role = Role(name='editor', description='编辑者')
        editor_role.permissions = [
            p for p in permissions if p.resource == 'content' or p.name == 'role:read'
        ]
        db.session.add(editor_role)
        
        user_role = Role(name='user', description='普通用户')
        user_role.permissions = [
            p for p in permissions if p.name in ['content:read', 'user:read']
        ]
        db.session.add(user_role)
        
        # 创建用户
        admin_user = User(username='admin', email='admin@example.com', password='password')
        admin_user.roles = [admin_role]
        db.session.add(admin_user)
        
        editor_user = User(username='editor', email='editor@example.com', password='password')
        editor_user.roles = [editor_role]
        db.session.add(editor_user)
        
        normal_user = User(username='user', email='user@example.com', password='password')
        normal_user.roles = [user_role]
        db.session.add(normal_user)
        
        db.session.commit()
    
    def _get_token(self, username, password):
        """获取用户的访问令牌"""
        response = self.client.post(
            '/auth/login',
            data=json.dumps({'username': username, 'password': password}),
            content_type='application/json'
        )
        data = json.loads(response.data)
        return data.get('access_token')
    
    def test_public_api(self):
        """测试公开API"""
        response = self.client.get('/api/test/public')
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
    
    def test_authenticated_api(self):
        """测试需要认证的API"""
        # 未认证访问
        response = self.client.get('/api/test/authenticated')
        self.assertEqual(response.status_code, 401)
        
        # 认证后访问
        token = self._get_token('user', 'password')
        response = self.client.get(
            '/api/test/authenticated',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
    
    def test_admin_api(self):
        """测试需要管理员权限的API"""
        # 普通用户访问
        token = self._get_token('user', 'password')
        response = self.client.get(
            '/api/test/admin',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 403)  # 权限不足
        
        # 管理员访问
        token = self._get_token('admin', 'password')
        response = self.client.get(
            '/api/test/admin',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
    
    def test_editor_api(self):
        """测试需要编辑者角色的API"""
        # 普通用户访问
        token = self._get_token('user', 'password')
        response = self.client.get(
            '/api/test/editor',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 403)  # 权限不足
        
        # 编辑者访问
        token = self._get_token('editor', 'password')
        response = self.client.get(
            '/api/test/editor',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
        
        # 管理员也可以访问（因为有所有权限）
        token = self._get_token('admin', 'password')
        response = self.client.get(
            '/api/test/editor',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
    
    def test_permission_api(self):
        """测试需要特定权限的API"""
        # 普通用户访问
        token = self._get_token('user', 'password')
        response = self.client.get(
            '/api/test/permission',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 403)  # 权限不足
        
        # 编辑者访问（有content:publish权限）
        token = self._get_token('editor', 'password')
        response = self.client.get(
            '/api/test/permission',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
    
    def test_user_management(self):
        """测试用户管理API"""
        # 管理员获取用户列表
        token = self._get_token('admin', 'password')
        response = self.client.get(
            '/api/users',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
        self.assertEqual(len(data['users']), 3)  # 三个测试用户
        
        # 普通用户获取用户列表（有user:read权限）
        token = self._get_token('user', 'password')
        response = self.client.get(
            '/api/users',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        
        # 编辑者获取用户列表（无user:read权限）
        token = self._get_token('editor', 'password')
        response = self.client.get(
            '/api/users',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 403)  # 权限不足
    
    def test_role_management(self):
        """测试角色管理API"""
        # 管理员获取角色列表
        token = self._get_token('admin', 'password')
        response = self.client.get(
            '/api/roles',
            headers={'Authorization': f'Bearer {token}'}
        )
        self.assertEqual(response.status_code, 200)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
        self.assertEqual(len(data['roles']), 3)  # 三个测试角色
        
        # 创建新角色
        response = self.client.post(
            '/api/roles',
            headers={'Authorization': f'Bearer {token}'},
            data=json.dumps({
                'name': 'guest',
                'description': '访客角色',
                'permissions': ['content:read']
            }),
            content_type='application/json'
        )
        self.assertEqual(response.status_code, 201)
        data = json.loads(response.data)
        self.assertEqual(data['status'], 'success')
        self.assertEqual(data['role']['name'], 'guest')
        
        # 普通用户尝试创建角色（无role:create权限）
        token = self._get_token('user', 'password')
        response = self.client.post(
            '/api/roles',
            headers={'Authorization': f'Bearer {token}'},
            data=json.dumps({
                'name': 'test_role',
                'description': '测试角色'
            }),
            content_type='application/json'
        )
        self.assertEqual(response.status_code, 403)  # 权限不足


if __name__ == '__main__':
    unittest.main()